from backend.eform.utils import checkCanDelete, checkCanEndorse, checkCanVerify, getClientIP, resetEformCheckState
from backend.eform.hierarchy_checksheet import HierarchyChecksheet
from os import scandir
from django.shortcuts import redirect, render
from django.urls import reverse
from rest_framework.decorators import api_view
from django.http import Http404, HttpResponseForbidden
from .models import *
# from cews.models import  DeviceList, Imte, LocationList, PairUpModel, WorkOrderList, WorkOrderList_Imte, StationList
# from cews.models import *
import datetime
import json
import backend.eform.builder_fields as bf
from django.conf import settings
from django.db.models import Q
from backend.eform.forms import copySchemaForm, seachEform

from django.db.models.deletion import ProtectedError

from logger.createlogger import create_logger

logger = create_logger(__name__)

## TODO: REVAMP THIS
# _HC = HierarchyChecksheet()
# if _HC.hc_dict=={}:
#     _HC.hc_dict = _HC.loadFromCsv()
#     _HC.saveAsJson()

def eformRoutingView(request,workorder_pk):
    """
        redirect user to 
        1. choese new form for workoredere
        2. existing form for the workorder
        3. for verifer or endorser to check the form
    """
    ##
    context = {}
    wo = WorkOrderList.objects.filter(pk=workorder_pk).select_related('brokenpart').first()
    # wo not found return to last page
    next = request.GET.get('next',False)
    showall = request.GET.get('showall',False)
    if showall=='true' or showall=='True' :
        showall=True
    else:
        showall=False

    if not wo:
        if not next:
            raise Http404()
        return redirect(next)

    ## TODO: found the form base on the hirecy 
    # concatch hc key
    # device = DeviceList.objects.filter(id=wo.brokenpart_id).first()
    

    eform = Eform.objects.filter(workOrderList_pk=wo.pk).first()
    if eform:
        ## redirect user to existing form
        ## now user can verify themself
        if eform.doneDate:
            return redirect(reverse('eform:checkEform',kwargs={'pk':eform.pk})+f"?next={next}")
        
        # if request.user.id == eform.doneby_id:
        return redirect(reverse('eform:eformView',kwargs={'pk':eform.pk})+f"?next={next}")


    ## filter eform by hkey
    hkey = wo.brokenpart.HKey
    ##  render eform list page for user select a correct form  
    cs = False
    if hkey:
        cs = _HC.findChecksheets(hkey)
    # if cs:
    if cs and not showall:
        es = EformSchema.objects.all().filter(formNo__in=cs).order_by('formNo')
        if not es:
            es = EformSchema.objects.all().order_by('formNo')    
    else:
        es = EformSchema.objects.all().order_by('formNo')


    # search eform
    if 'searcheform' in request.GET:
        searcheform = seachEform(request.GET)
        if searcheform.is_valid():
            search_field = request.GET.get('search', '')
            es = es.filter(Q(formNo__icontains=search_field)|Q(title__icontains=search_field)|Q(ref__icontains=search_field))
        else:
            logger.debug("searcheform is invalid")


    eforms = [e for e in es if e.enable]

    context['workOrder_id'] = workorder_pk
    context['eforms'] = eforms
    context['wo'] = wo
    context['showall'] = showall
    context['searcheform'] = seachEform()
    
    return render(request,'chooseForm.html',context)

def eformSchemaView(request,pk):
    context={}
    es = EformSchema.objects.get(pk=pk)
    if not es:
        raise Http404()

    efs = Eform.objects.filter(eformSchema=es)
    context['eforms'] = efs
    context['es'] = es
    
    return render(request,'eformSchemaView.html',context)


def checkEformView(request,pk): ## form view for verify and endorse
    
    ## get eform
    eform = Eform.objects.get(pk=pk)
    message = False
    check_require = False
    check_type = 'None'## verify  or endorsor
    color= 'success'
    check_string = '' ## use to display current checkstate text on UI
    eformFile = EformFile.objects.filter(eform=eform)
    endorse_required = eform.eformSchema.endorsor_require
    revise_enable =  False


    # if request.POST and endorse_required:
    if request.POST:
        ## determine verify or endorsor 
        action = request.POST.get('action',False)
        ## handle check as other user
        user_id = request.POST.get('user_id',False)
        is_check_as_other = user_id != False and user_id != '-1'
        selected_user = request.user
        if is_check_as_other:
            user = User.objects.get(pk=user_id)
            if user:
                selected_user = user
    
        logger.debug(action)
        print(action)
        if action:
            if action =='verify':
                if checkCanVerify(selected_user):
                    ## check user cannot be dupilcated
                    if not eform.checkUserDuplication(selected_user.id):
                        eform.verifiedby_id = selected_user.id
                        eform.verifiedDate = datetime.datetime.now()

                        ## depreciated, if the form endorsor_require == False, no verify and endorse needed
                        # if eform.eformSchema.endorsor_require == False:
                        #     ## if not require to endros, auto endorse
                        #     eform.endorsedby_id = selected_user.id
                        #     eform.endorsedDate = datetime.datetime.now()

                        message ="Verified."
                    else:
                        message="Verify user duplicated."
                        color='warning'
                else:
                    message = "Verify Fail, Insufficient Permission."
                    color="warning"

            elif action =='endorse':
                # print(eform.workOrderList.next_step.stationName== 'FINAL INSPECTION')
                if checkCanEndorse(selected_user):
                    ## check user cannot be dupilcated
                    if not eform.checkUserDuplication(selected_user.id):
                        if eform.workOrderList.next_step.stationName == 'FINAL INSPECTION':
                            eform.endorsedby_id = selected_user.id
                            eform.endorsedDate = datetime.datetime.now()
                            
                            message = "Endorsed."
                        else:
                            message = "You can ENDORSE the form ONLY when work order in FINAL INSPECTION stage"
                            color='warning'
                    else:
                        message="Endorse user duplicated."
                        color='warning'
                else:
                    message = "Endorse Fail, Insufficient Permission."
                    color="warning"

            elif action =='delete':
                if checkCanDelete(request.user):
                    updateWOStatus(eform.workOrderList, eform)
                    return deleteEform(eform)
                else:
                    message="Delete Fail, Insufficient Permission."
                    color="warning"

            elif action =='reset':
                if checkCanVerify(request.user) or checkCanEndorse:
                    resetEformCheckState(eform)
                    print('reset form')
                    updateWOStatus(eform.workOrderList, eform)
                    return redirect(reverse("workstation_wo",kwargs={'cewso':eform.workOrderList}))
                else:
                    message="Reset Approval State Fail, Insufficient Permission."
                    color='warning'
            elif action == 'revise':
                revise_enable = True
            
            elif action =="save":
                updateEform(request,eform)
                message="Saved!"

            else:
                message= "Saved"

            otr = request.POST.get('overall_test_result',False)
            if otr:
                eform.overall_test_result = otr
               
            ## update eform
            if eform.workOrderList:
                updateWorkOrderFields(eform.workOrderList,request)
            eform.save()
        # pass


    if endorse_required:
        if not eform.verifiedby:
            check_require = True
            check_type = 'verify'
            check_string = 'Verify'

        elif  eform.eformSchema.endorsor_require and not eform.endorsedby:
            check_require = True
            check_type = 'endorse'
            check_string = 'Endorse'

    ## TODO: Revamp this
    # wo_imte = WorkOrderList_Imte.objects.filter(workOrderList=eform.workOrderList)
    wo_imte = []
    rlog = ReviseLog.objects.filter(eform_pk=eform.id)
    
    context={
        'eform':eform,
        'rlog':rlog,
        'eformFile':eformFile,
        ## use eformSchema.formSchema insteat of extFormSchema
        'formSchema': json.dumps(eform.eformSchema.formSchema),
        'check_require':check_require,
        'check_type':check_type,
        'check_string':check_string,
        'message': message,
        'color':color,
        'imtes': wo_imte,
        'revise_enable':revise_enable
    }
    
    updateWOStatus(eform.workOrderList, eform)

    return render(request,'checkEform.html',context)

def listView(request):
    eformTemplates = EformSchema.objects.all().order_by('formNo')
    context = {
        'eforms':eformTemplates,
        'new':int(request.GET.get('new',False))
    }
    return render(request,'list.html',context)

def eformPrintView(request,pk):
    ## get eform
    eform = Eform.objects.get(pk=pk)
    if not eform:
        raise Http404()
    ## TODO: Revamp this
    # wo_imte = WorkOrderList_Imte.objects.filter(workOrderList=eform.workOrderList)
    wo_imte = []
    eformFile = EformFile.objects.filter(eform=eform)
    context={
        'eform':eform,
        ## use formSchema instead of extFormSchema
        'formSchema': json.dumps(eform.eformSchema.formSchema),
        'imtes': wo_imte,
        'eformFile':eformFile
    }
    return render(request,'eformPrintView.html',context)

def eformView(request,pk): ## form view
    
    ## get eform
    message = False
    color = 'success'
    eform = Eform.objects.get(pk=pk)
    if not eform:
        raise Http404()

    if not eform.workOrderList_pk:
        raise Http404()
    
    if request.POST:
        ## TODO: handle delete
        action = request.POST.get('action')
        print(request.POST)
        print(action)
        if action == 'done':
            eform.doneby_id = request.user.id
            updateEform(request,eform) 
            progress = eform.getProgress
            
            if (isinstance(progress,(float,int)) and progress >= 100 ):
                eform.doneDate = datetime.datetime.now()
                message="Form Done"
            else:
                message = "Progress not 100%, please fill all required fields."
                color="warning"
            if isinstance(progress,(bool)) and progress == False:
                eform.doneDate = datetime.datetime.now()
                message="Form Done"
                color="success"
            eform.save()

        if action == 'save':
            updateEform(request,eform)  
            message="Saved"

        if action=='delete':
            updateWOStatus(eform.workOrderList, eform)
            return deleteEform(eform)
            # wo_pk = eform.workOrderList.pk
            # eform.workOrderList = None
            # eform.save()
            # return redirect(reverse('eform:eformRoutingView',kwargs={'workorder_pk':wo_pk}))
    ## TODO: Revamp this
    # wo_imte = WorkOrderList_Imte.objects.filter(workOrderList=eform.workOrderList,due_date__gt=datetime.datetime.now())
    wo_imte = []
    is_psu = wo_imte.filter(imte_type__in=("P","p")).count() >0
    is_meter = wo_imte.filter(imte_type__in=("M","m")).count()>0
    # eform file
    eformFile = EformFile.objects.filter(eform=eform)
    # locations = LocationList.objects.all()
    ## TODO: Revamp this
    locations = []

    ## get paired ip
    # clientIp = getClientIP(request)
    ODI = False
    # if clientIp:
    
    
    ## TODO:Revamp this
    # pm = PairUpModel.objects.filter(tab_user = request.user).first()
    # if pm:
    #     ODI = pm.tableip

    ## revise log - rlog

    rlog = ReviseLog.objects.filter(eform_pk=eform.id)



    context={
        'eform':eform,
        'rlog':rlog,
        ## use formSchema instead of extFormSchema
        'formSchema': json.dumps(eform.eformSchema.formSchema),
        # 'OCR_DETECTION_IP': settings.OCR_DETECTION_IP,
        'OCR_DETECTION_IP': ODI,
        'message':message,
        'color':color,
        'imtes': wo_imte,
        'eformFile':eformFile,
        'is_psu': is_psu,
        'is_meter':is_meter,
        'psu' : wo_imte.filter(imte_type__in=("P","p")).first(),
        'meter' : wo_imte.filter(imte_type__in=("M","m")).first(),
        'locations':locations,
    }
    logger.debug(f'ODI:{ODI}')

    updateWOStatus(eform.workOrderList, eform)

    return render(request,'eformView.html',context)


def newEformView(request):
    """
        create a new eform with eformSchema_id 
        @param workOrderList_pk: String of workorder, used to query information 
    """
    context = {}
    
    eformSchema_id = request.POST.get('eformSchema_id',False)
    workOrderList_pk = request.POST.get('wo_id',False)

    ## TODO: Revamp this
    raise Exception('Not implemented')
    # workOrder = WorkOrderList.objects.get(pk=workOrderList_pk)
    
    eform = createEform(request,eformSchema_id,workOrder)

    if not eform:
        print('eform not found')
        raise Http404()

    
    return redirect(reverse('eform:eformView',kwargs={'pk':eform.id}))

def schemaBuilderEditView(request,pk):
    # if request.POST:
    #     postFormTemplate(request)
    context = {}
    context['components'] = json.dumps(bf.getComponents())
    eformSchema = EformSchema.objects.get(id=pk)
    if not eformSchema:
        return Http404()
    
    if (updateFormTemplate(request,eformSchema)):
        eformSchema = EformSchema.objects.get(id=pk)
    else:
        context['message'] = 'Cannot Save Form Schema Please Try Again'
    
    context['eform']=eformSchema
    
    return render(request,'builder_edit.html',context)

def schemaBuilderNewView(request):
    context = {}
    context['components'] = json.dumps(bf.getComponents())
    if request.POST:
        newEform = postFormTemplate(request)
        # print(newEform)
        return redirect(reverse('eform:list')+f'?new={newEform.id}')
    # eform = EformSchema.objects.filter(_id=pk)v
    # print(eform.pk)

    return render(request,'builder_new.html',context)


def updateFormTemplate(request,eformSchema):
    schemaJson = request.POST.get('dataJson',False)
    ## Meta data
    form_title = request.POST.get('form_title',False)
    form_no = request.POST.get('form_no',False)
    ref = request.POST.get('ref',False)
    enable = request.POST.get('enable',False)
    endorsor_require = request.POST.get('endorsor_require',False)
    form_issue_date = request.POST.get('form_issue_date',False)
    issue = request.POST.get('issue',False)
    if schemaJson:
        if form_title:
            eformSchema.title = form_title
        if form_no:
            eformSchema.formNo = form_no
        if ref:
            eformSchema.ref = ref
        if endorsor_require:
            eformSchema.endorsor_require = endorsor_require == 'Yes'
        if enable:
            eformSchema.enable = enable == 'Yes'
        if issue or issue=="": 
            eformSchema.issue=issue
        if form_issue_date or form_issue_date=="":
            if form_issue_date=="":
                eformSchema.form_issue_date = None
            else:
                eformSchema.form_issue_date = form_issue_date
            
        eformSchema.formSchema = json.loads(schemaJson)
        eformSchema.updated = datetime.datetime.now()
        eformSchema.save()

        return True
    else:
        return False


def postFormTemplate(request):
    # checkUserValid(request)
    ## Check permission
    print(request.POST)
    
    schemaJson = request.POST.get('dataJson',False)
    form_title = request.POST.get('form_title',False)
    form_no = request.POST.get('form_no',False)
    ref = request.POST.get('ref',False)
    endorsor_require = request.POST.get('endorsor_require',False)
    form_issue_date = request.POST.get('form_issue_date',False)
    issue = request.POST.get('issue',False)
    if schemaJson:
        formSchema = json.loads(schemaJson)
        eformSchema = EformSchema(
            title=form_title,
            formNo=form_no,
            ref = ref,
            endorsor_require=endorsor_require == 'Yes',
            formSchema=formSchema,
        )
        
        if issue:
            eformSchema.issue= issue

        if form_issue_date:
            if form_issue_date=="":
                eformSchema.form_issue_date = None
            else:
                eformSchema.form_issue_date = form_issue_date
    
        eformSchema.save()
        print(eformSchema.form_issue_date)
        # print(schemaJson)
        # print(eformSchema._id)
        return eformSchema
    else:
        return False
        

def createEform(request,eformSchema_id,workOrder):
    """
        create eform with 
        @param {string,int} eformSchema_id
        @param {WorkOrderList} workOrder
    """
    eform  = Eform()
    eformSchema = EformSchema.objects.get(pk=eformSchema_id)
    eform.eformSchema = eformSchema
    eform.extFormSchema = eformSchema.formSchema
    eform.doneby_id = request.user.id
    fd = getFormDataFromWorkOrder(workOrder)
    eform.formData =fd
    eform.workOrderList_pk = workOrder.pk
    
    eform.save()
    return eform

def getFormDataFromWorkOrder(workOrder):
    """
        Returns a formData Dictionary
        @param {WorkOrderList}
    """
    ret = {}
    ret = bf.getFormData(workOrder)
    
    ret['serialNo'] = workOrder.brokenpart.serialno

    return ret
    

def updateWorkOrderFields(wo,request):
    """
        @params {WorkOrderList} wo
        @params {HttpRequest} request
        update wo failure symptom, finding, action and remarks
    """
    print(request.POST)
    failure_sym = request.POST.get('wo_failure_sym',False)
    finding = request.POST.get('wo_finding',False)
    action = request.POST.get('wo_action',False)
    remarks = request.POST.get('wo_remarks',False)

    failure_sym = request.POST.get('wo_failure_sym',False)
    location = request.POST.get('wo_location',False)
    received_date = request.POST.get('wo_received_date',False)
    line_w_order = request.POST.get('wo_line_w_order',False)
    checkout_date = request.POST.get('wo_checkout_date',False)

    finding_opt = request.POST.get('wo_finding_opt',False)
    fault_opt = request.POST.get('wo_fault_opt',False)
    fault_action = request.POST.get('wo_fault_action',False)

    if finding_opt:
        wo.finding_opt = finding_opt
        if finding_opt!='2':
            wo.fault_opt = None
            
    if fault_opt:
        wo.fault_opt = fault_opt

    wo.fault_action = fault_action

    
    if failure_sym:
        wo.failure_sym = failure_sym
    if finding:
        wo.finding = finding
    if action:
        wo.action = action
    if remarks:
        wo.remarks = remarks
    ## TODO: update location revamp this
    # if location:
    #     loc = LocationList.objects.filter(id=location).first()
    #     if loc:
    #         wo.location = loc
    if received_date:
        wo.received_date = received_date
    if line_w_order:
        wo.line_w_order = line_w_order
    if checkout_date:
        wo.checkout_date = checkout_date

    wo.save()


def updateEform(request,eform):
    """
        serialize dataJson to Array of FormData  and store to the eform
        @param: eform 
    """
    print(request.POST)
    dataJson = request.POST.get('dataJson',False)
    test_result = request.POST.get('overall_test_result',False)
    if not dataJson:
        return False
    
    data = json.loads(dataJson)
    if test_result:
        eform.overall_test_result = test_result

    eform.formData = data
    
    eform.save()
    
    if eform.workOrderList:
        updateWorkOrderFields(eform.workOrderList,request)
    ## TODO: put edit log

    return eform
    
    
def deleteEform(eform):
    wo_pk = eform.workOrderList_pk
    eform.workOrderList_pk = None
    eform.save()
    ## TODO: put delete log
    return redirect(reverse('eform:eformRoutingView',kwargs={'workorder_pk':wo_pk}))


def schemaBuilderCopyView(request):
    context = {}
    copyschemaform=copySchemaForm()
    context['copyschemaform'] = copyschemaform
    if request.method=="POST" and "copyschemaform" in request.POST:
        copyschemaform = copySchemaForm(request.POST)
        pk = request.POST.get('formNo', None)
        if pk:
            print(f"{pk=}")
            es = EformSchema.objects.get(pk=pk)
            print(f"{es=}")
            es.pk = None
            es.id = None
            es.save()
            # es=EformSchema.objects.create(title="title", formNo="formNo", ref="ref", issue="issue", formSchema={}, endorsor_require=False)
            # es.save()
            return redirect(reverse('eform:schemaBuilder',kwargs={'pk':es.pk}))
    return render(request,'copyschema.html',context)

def deleteSchemaBuilder(request, pk):
    context = {}
    print("request.method", request.method)
    eformSchema = EformSchema.objects.get(id=pk)
    if request.method=="POST":
        try:
            eformSchema.delete()
            return redirect(reverse('eform:list'))
        except ProtectedError as e:
            err_msg="This schema is used by other eform. It is not allowed to delete."
            context['err_msg'] = err_msg

    context['es'] = eformSchema
    return render(request,'deleteschema.html',context)

def updateWOStatus(wo_instance, eform):
    e_form_done=eform.doneDate != None
    e_form_verified=eform.verifiedDate != None
    e_form_endorsed=eform.endorsedDate != None

    print("*"*30)
    print(f"{e_form_done=}")
    print(f"{e_form_verified=}")
    print(f"{e_form_endorsed=}")
    ## TODO: Revamp this
    return 
    if eform.eformSchema.endorsor_require:
        if e_form_endorsed:
            wo_instance.next_step=StationList.objects.get(pk=4)
            wo_instance.wo_status=1
            if not wo_instance.checkout_date:
                wo_instance.checkout_date=timezone.now().today()

        elif e_form_verified:
            wo_instance.next_step=StationList.objects.get(pk=3)
            wo_instance.wo_status=0
        elif e_form_done:
            wo_instance.next_step=StationList.objects.get(pk=2)
            wo_instance.wo_status=0
        else:
            wo_instance.next_step=StationList.objects.get(pk=1)
            wo_instance.wo_status=0
    else:
        if e_form_done:
            wo_instance.next_step=StationList.objects.get(pk=4)
            wo_instance.wo_status=1
            if not wo_instance.checkout_date:
                wo_instance.checkout_date=timezone.now().today()
        else:
            wo_instance.next_step=StationList.objects.get(pk=1)
            wo_instance.wo_status=0

    print(wo_instance.checkout_date)
    wo_instance.updated_on = timezone.now()
    wo_instance.save(update_fields=['next_step', 'wo_status', 'checkout_date', 'updated_on'])
